package com.carrental.search.service.impl;

import com.carrental.common.api.PageResult;
import com.carrental.search.model.document.VehicleDocument;
import com.carrental.search.repository.VehicleRepository;
import com.carrental.search.service.VehicleSearchService;
import org.elasticsearch.common.unit.DistanceUnit;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.GeoDistanceSortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import lombok.extern.slf4j.Slf4j;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 车辆搜索服务实现类
 */
@Service
@ConditionalOnProperty(name = "spring.elasticsearch.repositories.enabled", havingValue = "true", matchIfMissing = true)
@Slf4j
public class VehicleSearchServiceImpl implements VehicleSearchService {

    @Resource
    private VehicleRepository vehicleRepository;

    @Resource
    private ElasticsearchOperations elasticsearchOperations;

    @Override
    public VehicleDocument saveVehicle(VehicleDocument vehicleDocument) {
        return vehicleRepository.save(vehicleDocument);
    }

    @Override
    public Iterable<VehicleDocument> saveVehicles(List<VehicleDocument> vehicleDocuments) {
        return vehicleRepository.saveAll(vehicleDocuments);
    }

    @Override
    public VehicleDocument getVehicleById(Long id) {
        Optional<VehicleDocument> optionalVehicle = vehicleRepository.findById(id);
        return optionalVehicle.orElse(null);
    }

    @Override
    public void deleteVehicleById(Long id) {
        vehicleRepository.deleteById(id);
    }

    @Override
    public PageResult<VehicleDocument> searchVehicles(String keyword, int pageNum, int pageSize) {
        Pageable pageable = PageRequest.of(pageNum - 1, pageSize);

        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();

        if (StringUtils.hasText(keyword)) {
            boolQuery.should(QueryBuilders.matchQuery("name", keyword))
                    .should(QueryBuilders.matchQuery("brand", keyword))
                    .should(QueryBuilders.matchQuery("model", keyword))
                    .should(QueryBuilders.matchQuery("type", keyword))
                    .should(QueryBuilders.matchQuery("description", keyword))
                    .minimumShouldMatch(1);
        } else {
            boolQuery.must(QueryBuilders.matchAllQuery());
        }

        NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withQuery(boolQuery)
                .withPageable(pageable)
                .withSort(SortBuilders.fieldSort("createTime").order(SortOrder.DESC))
                .build();

        SearchHits<VehicleDocument> searchHits = elasticsearchOperations.search(searchQuery, VehicleDocument.class);

        return convertToPage(searchHits, pageNum, pageSize);
    }

    @Override
    public PageResult<VehicleDocument> advancedSearchVehicles(Map<String, Object> params, int pageNum, int pageSize) {
        Pageable pageable = PageRequest.of(pageNum - 1, pageSize);

        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();

        // 处理各种搜索参数
        if (params.containsKey("keyword") && StringUtils.hasText((String) params.get("keyword"))) {
            String keyword = (String) params.get("keyword");
            boolQuery.should(QueryBuilders.matchQuery("name", keyword))
                    .should(QueryBuilders.matchQuery("brand", keyword))
                    .should(QueryBuilders.matchQuery("model", keyword))
                    .should(QueryBuilders.matchQuery("type", keyword))
                    .should(QueryBuilders.matchQuery("description", keyword))
                    .minimumShouldMatch(1);
        }

        if (params.containsKey("brand") && StringUtils.hasText((String) params.get("brand"))) {
            boolQuery.must(QueryBuilders.termQuery("brand", params.get("brand")));
        }

        if (params.containsKey("model") && StringUtils.hasText((String) params.get("model"))) {
            boolQuery.must(QueryBuilders.termQuery("model", params.get("model")));
        }

        if (params.containsKey("type") && StringUtils.hasText((String) params.get("type"))) {
            boolQuery.must(QueryBuilders.termQuery("type", params.get("type")));
        }

        if (params.containsKey("status") && params.get("status") != null) {
            boolQuery.must(QueryBuilders.termQuery("status", params.get("status")));
        }

        if (params.containsKey("seats") && params.get("seats") != null) {
            boolQuery.must(QueryBuilders.termQuery("seats", params.get("seats")));
        }

        if (params.containsKey("transmissionType") && StringUtils.hasText((String) params.get("transmissionType"))) {
            boolQuery.must(QueryBuilders.termQuery("transmissionType", params.get("transmissionType")));
        }

        if (params.containsKey("fuelType") && StringUtils.hasText((String) params.get("fuelType"))) {
            boolQuery.must(QueryBuilders.termQuery("fuelType", params.get("fuelType")));
        }

        if (params.containsKey("minPrice") && params.get("minPrice") != null &&
                params.containsKey("maxPrice") && params.get("maxPrice") != null) {
            boolQuery.must(QueryBuilders.rangeQuery("dailyRent")
                    .gte(params.get("minPrice"))
                    .lte(params.get("maxPrice")));
        } else if (params.containsKey("minPrice") && params.get("minPrice") != null) {
            boolQuery.must(QueryBuilders.rangeQuery("dailyRent").gte(params.get("minPrice")));
        } else if (params.containsKey("maxPrice") && params.get("maxPrice") != null) {
            boolQuery.must(QueryBuilders.rangeQuery("dailyRent").lte(params.get("maxPrice")));
        }

        if (params.containsKey("minRating") && params.get("minRating") != null) {
            boolQuery.must(QueryBuilders.rangeQuery("rating").gte(params.get("minRating")));
        }

        if (params.containsKey("minYear") && params.get("minYear") != null &&
                params.containsKey("maxYear") && params.get("maxYear") != null) {
            boolQuery.must(QueryBuilders.rangeQuery("year")
                    .gte(params.get("minYear"))
                    .lte(params.get("maxYear")));
        } else if (params.containsKey("minYear") && params.get("minYear") != null) {
            boolQuery.must(QueryBuilders.rangeQuery("year").gte(params.get("minYear")));
        } else if (params.containsKey("maxYear") && params.get("maxYear") != null) {
            boolQuery.must(QueryBuilders.rangeQuery("year").lte(params.get("maxYear")));
        }

        if (params.containsKey("storeId") && params.get("storeId") != null) {
            boolQuery.must(QueryBuilders.termQuery("storeId", params.get("storeId")));
        }

        if (params.containsKey("recommended") && params.get("recommended") != null) {
            boolQuery.must(QueryBuilders.termQuery("recommended", params.get("recommended")));
        }

        // 处理排序
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder()
                .withQuery(boolQuery)
                .withPageable(pageable);

        if (params.containsKey("sortField") && StringUtils.hasText((String) params.get("sortField"))) {
            String sortField = (String) params.get("sortField");
            String sortOrder = "asc";
            if (params.containsKey("sortOrder") && StringUtils.hasText((String) params.get("sortOrder"))) {
                sortOrder = (String) params.get("sortOrder");
            }

            FieldSortBuilder sort = SortBuilders.fieldSort(sortField);
            if ("desc".equalsIgnoreCase(sortOrder)) {
                sort.order(SortOrder.DESC);
            } else {
                sort.order(SortOrder.ASC);
            }

            queryBuilder.withSort(sort);
        } else {
            // 默认按创建时间降序排序
            queryBuilder.withSort(SortBuilders.fieldSort("createTime").order(SortOrder.DESC));
        }

        // 处理位置搜索
        if (params.containsKey("latitude") && params.get("latitude") != null &&
                params.containsKey("longitude") && params.get("longitude") != null) {
            double latitude = Double.parseDouble(params.get("latitude").toString());
            double longitude = Double.parseDouble(params.get("longitude").toString());
            double distance = 10.0; // 默认10公里

            if (params.containsKey("distance") && params.get("distance") != null) {
                distance = Double.parseDouble(params.get("distance").toString());
            }

            boolQuery.must(QueryBuilders.geoDistanceQuery("location")
                    .point(latitude, longitude)
                    .distance(distance, DistanceUnit.KILOMETERS));

            // 按距离排序
            GeoDistanceSortBuilder geoSort = SortBuilders.geoDistanceSort("location", latitude, longitude)
                    .order(SortOrder.ASC)
                    .unit(DistanceUnit.KILOMETERS);

            queryBuilder.withSort(geoSort);
        }

        NativeSearchQuery searchQuery = queryBuilder.build();
        SearchHits<VehicleDocument> searchHits = elasticsearchOperations.search(searchQuery, VehicleDocument.class);

        return convertToPage(searchHits, pageNum, pageSize);
    }

    @Override
    public PageResult<VehicleDocument> searchVehiclesByBrand(String brand, int pageNum, int pageSize) {
        Pageable pageable = PageRequest.of(pageNum - 1, pageSize);

        NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withQuery(QueryBuilders.termQuery("brand", brand))
                .withPageable(pageable)
                .withSort(SortBuilders.fieldSort("createTime").order(SortOrder.DESC))
                .build();

        SearchHits<VehicleDocument> searchHits = elasticsearchOperations.search(searchQuery, VehicleDocument.class);

        return convertToPage(searchHits, pageNum, pageSize);
    }

    @Override
    public PageResult<VehicleDocument> searchVehiclesByType(String type, int pageNum, int pageSize) {
        Pageable pageable = PageRequest.of(pageNum - 1, pageSize);

        NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withQuery(QueryBuilders.termQuery("type", type))
                .withPageable(pageable)
                .withSort(SortBuilders.fieldSort("createTime").order(SortOrder.DESC))
                .build();

        SearchHits<VehicleDocument> searchHits = elasticsearchOperations.search(searchQuery, VehicleDocument.class);

        return convertToPage(searchHits, pageNum, pageSize);
    }

    @Override
    public PageResult<VehicleDocument> searchVehiclesByPriceRange(BigDecimal minPrice, BigDecimal maxPrice, int pageNum,
            int pageSize) {
        Pageable pageable = PageRequest.of(pageNum - 1, pageSize);

        NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withQuery(QueryBuilders.rangeQuery("dailyRent").gte(minPrice).lte(maxPrice))
                .withPageable(pageable)
                .withSort(SortBuilders.fieldSort("dailyRent").order(SortOrder.ASC))
                .build();

        SearchHits<VehicleDocument> searchHits = elasticsearchOperations.search(searchQuery, VehicleDocument.class);

        return convertToPage(searchHits, pageNum, pageSize);
    }

    @Override
    public PageResult<VehicleDocument> searchVehiclesByLocation(double latitude, double longitude, double distance,
            int pageNum, int pageSize) {
        Pageable pageable = PageRequest.of(pageNum - 1, pageSize);

        NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withQuery(QueryBuilders.geoDistanceQuery("location")
                        .point(latitude, longitude)
                        .distance(distance, DistanceUnit.KILOMETERS))
                .withPageable(pageable)
                .withSort(SortBuilders.geoDistanceSort("location", latitude, longitude)
                        .order(SortOrder.ASC)
                        .unit(DistanceUnit.KILOMETERS))
                .build();

        SearchHits<VehicleDocument> searchHits = elasticsearchOperations.search(searchQuery, VehicleDocument.class);

        return convertToPage(searchHits, pageNum, pageSize);
    }

    @Override
    public PageResult<VehicleDocument> getRecommendedVehicles(int pageNum, int pageSize) {
        Pageable pageable = PageRequest.of(pageNum - 1, pageSize);

        NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withQuery(QueryBuilders.termQuery("recommended", true))
                .withPageable(pageable)
                .withSort(SortBuilders.fieldSort("createTime").order(SortOrder.DESC))
                .build();

        SearchHits<VehicleDocument> searchHits = elasticsearchOperations.search(searchQuery, VehicleDocument.class);

        return convertToPage(searchHits, pageNum, pageSize);
    }

    @Override
    public PageResult<VehicleDocument> getHotVehicles(int pageNum, int pageSize) {
        Pageable pageable = PageRequest.of(pageNum - 1, pageSize);

        try {
            // 使用多个因素的复合查询
            BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();

            // 只查询可用状态的车辆
            boolQuery.must(QueryBuilders.termQuery("status", 1));

            // 按热门指数排序（如果有）或租赁次数排序
            NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
                    .withQuery(boolQuery)
                    .withPageable(pageable)
                    .withSort(SortBuilders.fieldSort("hotIndex").order(SortOrder.DESC).unmappedType("double"))
                    .withSort(SortBuilders.fieldSort("rentalCount").order(SortOrder.DESC))
                    .withSort(SortBuilders.fieldSort("rating").order(SortOrder.DESC))
                    .build();

            SearchHits<VehicleDocument> searchHits = elasticsearchOperations.search(searchQuery, VehicleDocument.class);

            PageResult<VehicleDocument> result = convertToPage(searchHits, pageNum, pageSize);

            // 如果没有数据，添加默认的热门车型数据
            if (result.getRecords() == null || result.getRecords().isEmpty()) {
                log.info("没有找到热门车型数据，返回默认数据");
                return getDefaultHotVehicles(pageNum, pageSize);
            }

            return result;
        } catch (Exception e) {
            log.error("查询热门车型失败", e);
            return getDefaultHotVehicles(pageNum, pageSize);
        }
    }

    @Override
    public PageResult<VehicleDocument> getHighRatedVehicles(Float minRating, int pageNum, int pageSize) {
        Pageable pageable = PageRequest.of(pageNum - 1, pageSize);

        NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withQuery(QueryBuilders.rangeQuery("rating").gte(minRating))
                .withPageable(pageable)
                .withSort(SortBuilders.fieldSort("rating").order(SortOrder.DESC))
                .build();

        SearchHits<VehicleDocument> searchHits = elasticsearchOperations.search(searchQuery, VehicleDocument.class);

        return convertToPage(searchHits, pageNum, pageSize);
    }

    @Override
    public PageResult<VehicleDocument> getNewestVehicles(int pageNum, int pageSize) {
        Pageable pageable = PageRequest.of(pageNum - 1, pageSize);

        NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withQuery(QueryBuilders.matchAllQuery())
                .withPageable(pageable)
                .withSort(SortBuilders.fieldSort("createTime").order(SortOrder.DESC))
                .build();

        SearchHits<VehicleDocument> searchHits = elasticsearchOperations.search(searchQuery, VehicleDocument.class);

        return convertToPage(searchHits, pageNum, pageSize);
    }

    @Override
    public VehicleDocument updateVehicleStatus(Long id, Integer status) {
        Optional<VehicleDocument> optionalVehicle = vehicleRepository.findById(id);
        if (optionalVehicle.isPresent()) {
            VehicleDocument vehicleDocument = optionalVehicle.get();
            vehicleDocument.setStatus(status);
            return vehicleRepository.save(vehicleDocument);
        }
        return null;
    }

    @Override
    public boolean incrementViewCount(Long id) {
        Optional<VehicleDocument> optionalVehicle = vehicleRepository.findById(id);
        if (optionalVehicle.isPresent()) {
            VehicleDocument vehicleDocument = optionalVehicle.get();
            // 初始化或增加浏览次数
            if (vehicleDocument.getViewCount() == null) {
                vehicleDocument.setViewCount(1);
            } else {
                vehicleDocument.setViewCount(vehicleDocument.getViewCount() + 1);
            }

            // 更新热门指数
            double hotIndex = calculateHotIndex(vehicleDocument);
            vehicleDocument.setHotIndex(hotIndex);

            vehicleRepository.save(vehicleDocument);
            return true;
        }
        return false;
    }

    /**
     * 将SearchHits转换为分页结果
     *
     * @param searchHits 搜索结果
     * @param pageNum    页码
     * @param pageSize   每页大小
     * @return 分页结果
     */
    private PageResult<VehicleDocument> convertToPage(SearchHits<VehicleDocument> searchHits, int pageNum,
            int pageSize) {
        List<VehicleDocument> vehicleDocuments = searchHits.getSearchHits().stream()
                .map(SearchHit::getContent)
                .collect(Collectors.toList());

        long totalHits = searchHits.getTotalHits();
        int totalPages = (int) Math.ceil((double) totalHits / pageSize);

        PageResult<VehicleDocument> page = new PageResult<>();
        page.setRecords(vehicleDocuments);
        page.setTotal((int) totalHits);
        page.setCurrent(pageNum);
        page.setSize(pageSize);
        page.setPages(totalPages);

        return page;
    }

    /**
     * 定期计算并更新车辆热门指数
     * 每天凌晨1点执行
     */
    @Scheduled(cron = "0 0 1 * * ?")
    public void updateHotIndex() {
        // 查询所有车辆
        Iterable<VehicleDocument> allVehicles = vehicleRepository.findAll();

        for (VehicleDocument vehicle : allVehicles) {
            // 计算热门指数
            double hotIndex = calculateHotIndex(vehicle);
            vehicle.setHotIndex(hotIndex);

            // 更新到ES
            vehicleRepository.save(vehicle);
        }
    }

    /**
     * 计算车辆热门指数
     * 综合考虑租赁次数、评分、浏览量等因素
     * 
     * @param vehicle 车辆文档
     * @return 热门指数
     */
    private double calculateHotIndex(VehicleDocument vehicle) {
        // 权重设置
        double rentalCountWeight = 0.5;
        double ratingWeight = 0.3;
        double viewCountWeight = 0.2;

        // 防止空值
        int rentalCount = vehicle.getRentalCount() != null ? vehicle.getRentalCount() : 0;
        float rating = vehicle.getRating() != null ? vehicle.getRating() : 0;
        int ratingCount = vehicle.getRatingCount() != null ? vehicle.getRatingCount() : 0;
        int viewCount = vehicle.getViewCount() != null ? vehicle.getViewCount() : 0;

        // 计算热门指数
        double hotIndex = rentalCountWeight * rentalCount +
                ratingWeight * rating * ratingCount +
                viewCountWeight * viewCount;

        return hotIndex;
    }

    /**
     * 获取默认的热门车型数据
     */
    private PageResult<VehicleDocument> getDefaultHotVehicles(int pageNum, int pageSize) {
        List<VehicleDocument> defaultVehicles = new ArrayList<>();

        // 添加默认车型数据
        VehicleDocument vehicle1 = new VehicleDocument();
        vehicle1.setId(1L);
        vehicle1.setName("奥迪A6L");
        vehicle1.setBrand("奥迪");
        vehicle1.setModel("A6L");
        vehicle1.setType("豪华轿车");
        vehicle1.setSeats(5);
        vehicle1.setDailyRent(new BigDecimal("399"));
        vehicle1.setStatus(1);
        defaultVehicles.add(vehicle1);

        VehicleDocument vehicle2 = new VehicleDocument();
        vehicle2.setId(2L);
        vehicle2.setName("丰田凯美瑞");
        vehicle2.setBrand("丰田");
        vehicle2.setModel("凯美瑞");
        vehicle2.setType("中型轿车");
        vehicle2.setSeats(5);
        vehicle2.setDailyRent(new BigDecimal("299"));
        vehicle2.setStatus(1);
        defaultVehicles.add(vehicle2);

        VehicleDocument vehicle3 = new VehicleDocument();
        vehicle3.setId(3L);
        vehicle3.setName("宝马X5");
        vehicle3.setBrand("宝马");
        vehicle3.setModel("X5");
        vehicle3.setType("SUV");
        vehicle3.setSeats(5);
        vehicle3.setDailyRent(new BigDecimal("599"));
        vehicle3.setStatus(1);
        defaultVehicles.add(vehicle3);

        VehicleDocument vehicle4 = new VehicleDocument();
        vehicle4.setId(4L);
        vehicle4.setName("别克GL8");
        vehicle4.setBrand("别克");
        vehicle4.setModel("GL8");
        vehicle4.setType("MPV");
        vehicle4.setSeats(7);
        vehicle4.setDailyRent(new BigDecimal("399"));
        vehicle4.setStatus(1);
        defaultVehicles.add(vehicle4);

        VehicleDocument vehicle5 = new VehicleDocument();
        vehicle5.setId(5L);
        vehicle5.setName("大众帕萨特");
        vehicle5.setBrand("大众");
        vehicle5.setModel("帕萨特");
        vehicle5.setType("中型轿车");
        vehicle5.setSeats(5);
        vehicle5.setDailyRent(new BigDecimal("269"));
        vehicle5.setStatus(1);
        defaultVehicles.add(vehicle5);

        VehicleDocument vehicle6 = new VehicleDocument();
        vehicle6.setId(6L);
        vehicle6.setName("本田CR-V");
        vehicle6.setBrand("本田");
        vehicle6.setModel("CR-V");
        vehicle6.setType("SUV");
        vehicle6.setSeats(5);
        vehicle6.setDailyRent(new BigDecimal("329"));
        vehicle6.setStatus(1);
        defaultVehicles.add(vehicle6);

        VehicleDocument vehicle7 = new VehicleDocument();
        vehicle7.setId(7L);
        vehicle7.setName("奔驰E级");
        vehicle7.setBrand("奔驰");
        vehicle7.setModel("E级");
        vehicle7.setType("豪华轿车");
        vehicle7.setSeats(5);
        vehicle7.setDailyRent(new BigDecimal("499"));
        vehicle7.setStatus(1);
        defaultVehicles.add(vehicle7);

        VehicleDocument vehicle8 = new VehicleDocument();
        vehicle8.setId(8L);
        vehicle8.setName("特斯拉Model 3");
        vehicle8.setBrand("特斯拉");
        vehicle8.setModel("Model 3");
        vehicle8.setType("纯电动");
        vehicle8.setSeats(5);
        vehicle8.setDailyRent(new BigDecimal("499"));
        vehicle8.setStatus(1);
        defaultVehicles.add(vehicle8);

        // 创建分页结果
        PageResult<VehicleDocument> pageResult = new PageResult<>();
        pageResult.setRecords(defaultVehicles.subList(0, Math.min(pageSize, defaultVehicles.size())));
        pageResult.setTotal(defaultVehicles.size());
        pageResult.setCurrent(pageNum);
        pageResult.setSize(pageSize);
        pageResult.setPages(1);

        return pageResult;
    }
}